<?php
/*
	+------------------------------------
	+ 基于角色控制的数据库方式验证类
	+------------------------------------
	+ 配置文件上相比官方提供的少了很多！详见config.php文件
	+ 在数据表上有官方原来的5个表变成现在的2个表
	+ 数据表的字段上相比起来更是少了很多！一个表只要两三个字段就可搞定了
	+ 权限配置上，不需要在考虑什么节点啊等级等问题！只要在配置文件里面写上要权限判断的操作方法后者是模块就可以了
	+ 在使用上和官方提供的类的使用方法是一样的！只是一些名字改了下而已，这点只要是我个人的习惯！
	+ 最主要的一点是：采用位运算的方式来进行权限控制！实现原理文件详见：right.php
	+------------------------------------
	+-------------------------------------------------------------
	+ 数据表：
		CREATE TABLE IF NOT EXISTS `r_role` (
		  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
		  `name` varchar(50) CHARACTER SET utf8 NOT NULL,	//角色昵称
		  `shell` int(32) unsigned NOT NULL,		//权限字段
		  `status` int(2) NOT NULL DEFAULT '1',		//状态字段
		  PRIMARY KEY (`id`)
		) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
	+--------------------------------------------------------------
		CREATE TABLE IF NOT EXISTS `r_user` (
		  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
		  `username` varchar(50) CHARACTER SET utf8 NOT NULL,
		  `nickname` varchar(50) CHARACTER SET utf8 NOT NULL,
		  `passwd` varchar(32) CHARACTER SET utf8 NOT NULL,
		  `rid` int(10) NOT NULL COMMENT '所在角色的id',		//所在角色表的id
		  PRIMARY KEY (`id`)
		) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
	+-------------------------------------------------------------
	+ 只要这两个表即可！当然这两个表的字段是最简单的，你还可以在添加自己要用的字段
	*/
//自定义的操作权限的类
class Right extends Think {
	
	//权限赋值操作
	public function authShell() {
		$rightShell = array ();
		$str = C ( 'REQUIRE_AUTH_MODULE' ) . ',' . C ( 'REQUIRE_AUTH_ACTION' );
		if (empty ( $str )) {
			return false;
		} else {
			$rightShell = array_unique ( explode ( ',', $str ) );
			for($i = 0; $i < count ( $rightShell ); $i ++) {
				if (empty ( $rightShell [$i] )) {
					unset ( $rightShell [$i] );
					continue;
				}
				DEFINE ( strtoupper ( $rightShell [$i] ), pow ( 2, $i ) );
			}
		}
	}
	
	//认证方法
	static public function authCheck($map, $model = '') {
		if (empty ( $model ))
			$model = C ( 'USER_AUTH_MODEL' );
		
		//使用给定的Map进行认证
		return M ( $model )->where ( $map )->find ();
	}
	
	//登录后直接缓存用户的权限
	static public function saveRight($authId = NULL) {
		//若没有主键，则从配置文件获取
		if ($authId === NULL) {
			$authId = $_SESSION [C ( 'USER_AUTH_KEY' )];
		}
		//若为登录时认证且非管理员账号
		if (C ( 'USER_AUTH_TYPE' ) == 1 && empty ( $_SESSION [C ( 'ADMIN_AUTH_KEY' )] )) {
			//获取操作权限进行缓存
			//echo "asdfasd";
			$_SESSION ['rightList'] = Right::getRight ( $authId );
			return;
		}
	}
	
	//检查当前操作是否需要权限认证
	static public function checkRight() {
		//检查是否开启了权限判断功能
		if (C ( 'USER_AUTH_ON' )) {
			//检查需要权限判断的模块，如果为空则说明没有模块需要权限判断
			if (C ( 'REQUIRE_AUTH_MODULE' ) != "") {
				$_model = array ();
				//获取所需要的判断的模块
				$_model = explode ( ',', strtoupper ( C ( 'REQUIRE_AUTH_MODULE' ) ) );
			} else {
				return false;
			}
			//如果需要权限判断的模块不等于空且当前模块在需要权限判断的模块之内
			if (! empty ( $_model ) && in_array ( strtoupper ( MODULE_NAME ), $_model )) {
				//检查需要权限判断的方法，如果为空说明没有需要权限判断的方法
				if (C ( 'REQUIRE_AUTH_ACTION' ) != "") {
					$_aciton = array ();
					//获取需要权限判断的方法
					$_action = explode ( ',', strtoupper ( C ( 'REQUIRE_AUTH_ACTION' ) ) );
				} else {
					return false;
				}
				//如果需要权限判断的方法不等于空且当前操作方法在需要权限判断的操作方法之内，则当前方法需要权限判断
				if (! empty ( $_action ) && in_array ( strtoupper ( ACTION_NAME ), $_action )) {
					return true;
				}
			} else {
				//权限判断模块等于空或者是当前模块不再需要判断的模块范围之内
				return false;
			}
		} else {
			return false;
		}
	}
	
	//权限认证的过滤方法
	static public function RightPass($app = APP_NAME) {
		self::authShell ();
		//判断是否需要认证
		if (Right::checkRight ()) {
			$action = ACTION_NAME;
			$module = MODULE_NAME;
			if (empty ( $_SESSION [C ( 'ADMIN_AUTH_KEY' )] )) {
				//非管理员需要认证
				if (C ( 'USER_AUTH_TYPE' ) == 2) {
					//实时认证模式
					$rightList = Right::getRight ( $_SESSION [C ( 'USER_AUTH_KEY' )] );
					//返回是否具有操作该方法的权限(bool),先判断是否具有操作该模块的权限
					return $rightList [$module] ? $rightList [$action] : false;
				} else {
					//如果是已经认证过的操作方法，则无需认证
					if ($_SESSION [MD5 ( $app . $module . $action )]) {
						return true;
					}
					//返回是否具有操作该方法的权限(bool),先判断是否具有操作该模块的权限
					$rightList = $_SESSION ['rightList'];
					eval ( '$act = ' . strtoupper ( $action ) . ';' );
					eval ( '$mod = ' . strtoupper ( $module ) . ';' );
					$_SESSION [MD5 ( $app . $module . $action )] = true; //保存需要认证但已经认证过的地址（APP->MODUL->ACTION）
					return ($rightList & $mod) ? ($rightList & $act) : false;
				}
			} else {
				//管理员无需认证
				return true;
			}
		} else {
			return true;
		}
	}
	
	//从数据库中获取指定用户的操作权限列表
	static public function getRight($authId) {
		self::authShell ();
		//实例化数据模型
		$role = M ( ucwords ( strtolower ( C ( 'USER_ROLE_TABLE' ) ) ) );
		//通过把用户表和角色权限表链表查询
		$prefix = strtolower ( C ( 'DB_PREFIX' ) );
		$role_table = strtolower ( C ( 'USER_ROLE_TABLE' ) );
		$user_table = strtolower ( C ( 'USER_AUTH_MODEL' ) );
		//通过登录产生的主键id来查找相关的权限
		$map [$prefix . $user_table . "." . $role->getPk ()] = $authId;
		$map [$prefix . $role_table . ".status"] = 1;
		$res = $role->join ( $prefix . $user_table . ' on ' . $prefix . $role_table . ".id = " . $prefix . $user_table . ".rid" )->where ( $map )->find ();
		$rightList = array ();
		if (C ( 'USER_AUTH_TYPE' ) == 1 && empty ( $_SESSION [C ( 'ADMIN_AUTH_KEY' )] )) {
			//登录认证模式
			return $res [C ( 'USER_RIGHT_FIELD' )];
		} else {
			//实时认证模式
			$action = ACTION_NAME;
			$module = MODULE_NAME;
			eval ( '$act = ' . strtoupper ( $action ) . ';' );
			eval ( '$mod = ' . strtoupper ( $module ) . ';' );
			//进行位运算判断授权
			$rightList [$module] = $res [C ( 'USER_RIGHT_FIELD' )] & $mod;
			$rightList [$action] = $res [C ( 'USER_RIGHT_FIELD' )] & $act;
			return $rightList;
		}
	}
}
?>